package view.editorview;

import java.awt.BasicStroke;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import controller.commoncontroller.ZoomWheelListener;
import locsi.UserSettings;
import model.LogicType;
import model.editormodel.EditorMessage;
import model.editormodel.EditorModel;
import model.editormodel.Input;
import model.editormodel.LogicEditorElement;
import model.editormodel.Output;
import view.UtilityLogicDesigns;
import view.UtilityConstants;
import view.commonview.CircuitTypeArea;
import view.commonview.ConnectorPath;
import view.commonview.InfoArea;
import view.commonview.LogicViewElement;
import view.commonview.TabbedPane;

/**
 * <b>Implementiert:</b> <code>Observer</code> <br>
 * <b>Erbt:</b> <code>JPanel</code> <br>
 * <b>In Verbindung stehende Klassen:</b>
 * <code>EditorModel, CircuitTypeArea, LogicViewElement, ConnectorPath, ComponentPanel</code>
 * <br>
 * <b>Ueberwachtes Objekt:</b> <code>EditorModel</code> <br>
 * <b>Funktion:</b> Visualisierung Bearbeitungsbereich <br>
 * <br>
 * Panel, auf dem die Schaltung visualisiert wird (Bearbeitungsbereich). Diese
 * Klasse ueberwacht das <code>EditorModel</code> und visualisiert die darauf
 * gespeicherten Logikelemente.
 * 
 * @author Team Locsi
 * 
 */
@SuppressWarnings("serial")
public class EditorArea extends JPanel implements Observer {

	/*
	 * Referenzen auf andere View-Objekte
	 */
	private InfoArea iArea;
	private EditorModel editorModel;
	private JScrollPane eScroller;
	private CircuitTypeArea typeArea;
	private ComponentPanel compPanel;
	private TabbedPane tabPane;

	/*
	 * Maps und Listen zum Speichern von Elementen der EditorArea (Bauteile,
	 * markierte Bauteile, Leitungen, markierte Leitungen, zu loeschende
	 * Leitungen)
	 */
	private Map<String, LogicViewElement> vElements;
	private Map<String, LogicViewElement> markedVElements;
	private List<ConnectorPath> paths;
	private List<ConnectorPath> markedPaths;
	private List<ConnectorPath> removedPaths;

	/*
	 * Variablen fuer das Markierungsrechteck
	 */
	private Rectangle2D markTangle;
	private double startXMarkTangle;
	private double startYMarkTangle;

	/*
	 * Leitung, die noch nicht fest zwischen einem Eingang und einem Ausgang
	 * gezeichnet ist
	 */
	private ConnectorPath newConnection;
	private Point2D startPointConnection;

	/*
	 * Verschiedene Linienarten fuer die paintComponent-Methode
	 */
	private BasicStroke s1;
	private BasicStroke s2;
	private BasicStroke s3;
	private BasicStroke s4;

	/*
	 * Variablen fuer das Raster
	 */
	private boolean showRaster = false;
	private boolean refreshRasterTemp = false;
	private int maxXPos = 800;
	private int maxYPos = 800;
	private BufferedImage raster;

	/*
	 * Sichtbarer Bereich der EditorArea als Rechteck
	 */
	private Rectangle2D visibleRect;

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>EditorArea</code>-Objekt.
	 * Dabei wird die <code>EditorArea</code> beim <code>EditorModel</code>
	 * -Objekt als <code>Observer</code> angemeldet.
	 * 
	 * @param eModel
	 *            <code>EditorModel</code> - Referenz auf
	 *            <code>EditorModel</code>
	 * @param cta
	 *            <code>CircuitTypeArea</code> - Referenz auf die
	 *            <code>CircuitTypeArea</code>
	 * @param compPanel
	 *            <code>ComponentPanel</code> - Referenz auf das
	 *            <code>ComponentPanel</code>
	 * 
	 * @param tabs
	 *            <code>TabbedPane</code> - Referenz auf das
	 *            <code>TabbedPane</code>
	 * 
	 * @param iArea
	 *            <code>InfoArea</code> - Referenz auf die <code>InfoArea</code>
	 */
	public EditorArea(EditorModel eModel, CircuitTypeArea cta,
			ComponentPanel compPanel, TabbedPane tabs, InfoArea iArea) {
		this.setLayout(null);
		this.setBackground(Color.WHITE);
		this.setPreferredSize(new Dimension(maxXPos, maxYPos));

		// Referenzen setzen
		this.iArea = iArea;
		this.compPanel = compPanel;
		this.tabPane = tabs;
		this.typeArea = cta;
		this.editorModel = eModel;
		this.editorModel.addObserver(this);
		this.vElements = new HashMap<String, LogicViewElement>();
		this.markedVElements = new HashMap<String, LogicViewElement>();
		this.paths = new ArrayList<ConnectorPath>();
		this.markedPaths = new ArrayList<ConnectorPath>();
		this.removedPaths = new ArrayList<ConnectorPath>();
		float[] dash_array = { 10, 10 };
		float[] dash_array2 = { 1, 5 };

		// basicstrokes anlegen - fuer paintcomponent-methode wichtig.
		// veschiedenen styles zum zeichnen der linien
		this.s1 = new BasicStroke(1);
		this.s2 = new BasicStroke(1f, BasicStroke.CAP_SQUARE,
				BasicStroke.JOIN_ROUND, 1f, dash_array, 0);
		this.s3 = new BasicStroke(0.8f / (float) tabs.getZoomFactor(),
				BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 1f,
				dash_array2, 0);
		this.s4 = new BasicStroke(1.3f);
		this.visibleRect = new Rectangle2D.Double();

		// adden des zoomwheellisteners
		this.addMouseWheelListener(new ZoomWheelListener(tabs));
	}

	/**
	 * Setzt den Stroke für das Raster neu
	 */
	private void refreshRasterStroke() {
		float[] dash_array2 = { 1, 5 };
		this.s3 = new BasicStroke(0.8f / (float) tabPane.getZoomFactor(),
				BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 1f,
				dash_array2, 0);
	}

	/**
	 * Methode die im Hintergrund des Bearbeitungsbereichs das Raster zeichnet,
	 * falls durch den Benutzer nicht anders vorgegeben
	 */
	public void paintRasterToImage() {
		// ueberpruefung ob raster neu gezeichnet werden soll
		if (refreshRasterTemp && showRaster) {
			// raster wird dann auf ein bufferedimage gezeichnet, welches im
			// hintergrund der editorarea liegt
			raster = new BufferedImage(Math.max(800, this.getWidth()),
					Math.max(800, this.getHeight()), BufferedImage.TYPE_INT_RGB);
			Graphics2D g2d = raster.createGraphics();
			g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);

			int pictureWidth = raster.getWidth();
			int pictureHeight = raster.getHeight();

			int counter = 1;
			g2d.setColor(Color.white);
			g2d.fillRect(0, 0, pictureWidth, pictureHeight);
			g2d.setColor(Color.LIGHT_GRAY);
			g2d.scale(tabPane.getZoomFactor(), tabPane.getZoomFactor());

			refreshRasterStroke();
			g2d.setStroke(s3);

			// zeichnet vertikale linien wie fuer den sichtbaren bereich der
			// editorarea notwendig sind
			// (raster)
			while (counter
					* (tabPane.getZoomFactor() * UtilityConstants.RASTER_SIZE) < this
						.getVisibleRect().height) {
				g2d.drawLine(0, counter * UtilityConstants.RASTER_SIZE,
						(int) (pictureWidth / tabPane.getZoomFactor()), counter
								* UtilityConstants.RASTER_SIZE);
				counter++;
			}
			counter = 1;
			// zeichnet horizontale linien wie fuer en sichtbaren bereich der
			// editorarea notwendig sind
			// (raster)
			while (counter
					* (tabPane.getZoomFactor() * UtilityConstants.RASTER_SIZE) < this
						.getVisibleRect().width) {
				g2d.drawLine(counter * UtilityConstants.RASTER_SIZE, 0, counter
						* UtilityConstants.RASTER_SIZE,
						(int) (pictureHeight / tabPane.getZoomFactor()));
				counter++;
			}
			g2d.dispose();
		}
	}

	/**
	 * Methode die aehnlich zur paintComponent Methode die Bauteile und
	 * Verbindungen zeichnet. Im Gegensatz zur paintComponent-Methode zeichnet
	 * diese Methode alle Bauteile und Verbindungen, nicht nur die sichtbaren.
	 * Der "Screenshot" wird in ein BufferedImage gezeichnet, welches
	 * zurueckgegeben wird
	 * 
	 * @param img
	 *            BufferedImage, in welches die Bauteile und Verbindungen
	 *            gezeichnet werden sollen
	 * @return img mit den gezeichneten Bauteilen und Verbindungen
	 */
	public BufferedImage paintToImage(BufferedImage img) {
		Graphics2D g2d = img.createGraphics();
		g2d.setColor(Color.white);
		g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
		g2d.setColor(Color.black);
		// falls durch benutzervorgabe nicht anders gewuenscht wird hier das
		// raster im hintergrund gezeichnet
		if (showRaster) {
			g2d.drawImage(raster, null, 0, 0);
		}

		// grafikeinstellungen fuers weichzeichnen der linien
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.scale(tabPane.getZoomFactor(), tabPane.getZoomFactor());
		g2d.setStroke(s1);
		// zeichnen der bauteile mit der privaten hilfsmethode drawGates
		g2d.setStroke(s4);
		paintLogicViewElements(g2d, true);

		// zeichnen der verbindungen mit der privaten hilfsmethode
		// drawConnections
		g2d.setStroke(s1);
		paintConnections(g2d, true);

		// zeichnen der ein- und ausgaenge mit der privaten hilfsmethode
		// drawInputsAndOutputs
		paintInputsAndOutputs(g2d, true);

		// ueberpruefen, ob das markierungsrechteck gezeichnet werden muss
		// ggf. wird dieses dann gezeichnet
		if (markTangle != null) {
			g2d.setColor(Color.BLACK);
			g2d.setStroke(s2);
			g2d.draw(markTangle);
		}

		return img;
	}

	/**
	 * In dieser ueberschriebenen <code>paintComponent</code> Methode werden
	 * alle noetigen Zeichenoperationen fuer die <code>EditorArea</code>
	 * ausgefuehrt. Aus Effizienzgruenden werden dabei werden nur die Bauteile
	 * und Verbindungen gezeichnet, die im sichtbaren Bereich des ScrollPanes
	 * fuer die EditorArea liegen
	 */
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;
		// festlegen des sichtbaren bereichs der editorarea als rechteck
		visibleRect.setRect(
				eScroller.getViewport().getViewRect().x
						/ tabPane.getZoomFactor(),
				eScroller.getViewport().getViewRect().y
						/ tabPane.getZoomFactor(),
				eScroller.getViewport().getViewRect().width
						/ tabPane.getZoomFactor(), eScroller.getViewport()
						.getViewRect().height / tabPane.getZoomFactor());

		// ueberpruefung ob raster gezeichnet werden soll
		if (showRaster) {
			g2d.drawImage(raster, null, 0, 0);
		}

		// optionen zum weichzeichnen der linien
		if (UserSettings.doAntiAlias) {
			g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);
		}
		g2d.scale(tabPane.getZoomFactor(), tabPane.getZoomFactor());
		g2d.setStroke(s1);

		paths.removeAll(removedPaths);
		removedPaths.clear();

		// zeichnen der bauteile mit der privaten hilfsmethode drawGates
		g2d.setStroke(s4);
		paintLogicViewElements(g2d, false);

		// zeichnen der verbindungen mit der privaten hilfsmethode
		// drawConnections
		g2d.setStroke(s1);
		paintConnections(g2d, false);

		// zeichnen der ein- und ausgaenge mit der privaten hilfsmethode
		// drawInputsAndOutputs
		paintInputsAndOutputs(g2d, false);

		// ueberpruefen, ob das markierungsrechteck gezeichnet werden muss
		// ggf. wird dieses dann gezeichnet
		if (markTangle != null) {
			g2d.setColor(Color.BLACK);
			g2d.setStroke(s2);
			g2d.draw(markTangle);
		}
	}

	/**
	 * Private Hilfsmethode zum Zeichnen der Bauteile
	 * 
	 * @param g2d
	 *            Graphics2D Objekt aus der paintComponent-Methode
	 * 
	 * @param doNotClip
	 *            Flag, die festlegt, ob nur der sichtbare Ausschnitt oder alle
	 *            Elemente, die sich auf der <code>EditorArea</code> befinden,
	 *            gezeichnet werden sollen (Bildfunktion)
	 */
	private void paintLogicViewElements(Graphics2D g2d, boolean doNotClip) {
		// durchlaufen der bauteile
		for (Map.Entry<String, LogicViewElement> vElement : vElements
				.entrySet()) {
			if (doNotClip
					|| vElement.getValue().getDesign().intersects(visibleRect)) {
				g2d.setColor(Color.WHITE);
				g2d.fill(vElement.getValue().getDesign());

				// ueberpruefen, ob element markiert ist oder nicht und
				// entsprechend
				// farbe der linie setzen
				if (vElement.getValue().isMarked()) {
					g2d.setColor(Color.RED);
				} else {
					g2d.setColor(Color.BLACK);
				}

				LogicType lType = editorModel.getCircuitModel()
						.getUnmodifableElementsOnEditor()
						.get(vElement.getValue().getElementsName()).getType();
				// zeichnen der bauteile
				if (lType == LogicType.NODE) {
					g2d.fill(vElement.getValue().getDesign());
					// falls eine lampe angeklickt wurde
				} else if (lType == LogicType.LAMP) {
					Color lineColor = g2d.getColor();
					g2d.setColor(UtilityConstants.LAMP_OFF_COLOR);
					g2d.fill(vElement.getValue().getDesign());
					g2d.setColor(lineColor);
					g2d.draw(vElement.getValue().getDesign());
					g2d.drawString(vElement.getValue().getElementsName(),
							(float) vElement.getValue().getSourceX() - 6,
					UserSettings.uglyLamp ?	(float) vElement.getValue().getSourceY() - 3 : (float) vElement.getValue().getSourceY() + 20);
					// falls ein schalter angeklickt wurde
				} else if (lType == LogicType.SWITCH) {
					// g2d.setColor(Color.BLACK);
					g2d.draw(vElement.getValue().getDesign());
					g2d.drawString(vElement.getValue().getElementsName(),
							(float) vElement.getValue().getSourceX() - 12,
							(float) vElement.getValue().getSourceY() - 5);
				} else if (lType == LogicType.CLOCK
						|| lType == LogicType.SELFDEFINED) {
					g2d.draw(vElement.getValue().getDesign());
					g2d.drawString(vElement.getValue().getElementsName(),
							(float) vElement.getValue().getSourceX() - 6,
							(float) vElement.getValue().getSourceY() - 3);

					// bei selbstdefinierten bauteilen werden zudem die kuerzel
					// der namen der eingaenge und ausgaenge gezeichnet
					if (lType == LogicType.SELFDEFINED) {
						// durchlaufen er eingaenge
						for (Input inp : editorModel.getCircuitModel()
								.getUnmodifableElementsOnEditor()
								.get(vElement.getValue().getElementsName())
								.getInputs().values()) {

							// es werden nur die ersten 3 buchstaben des
							// inputnamens angezeigt
							g2d.drawString(
									inp.getOuterName().substring(
											0,
											Math.min(inp.getOuterName()
													.length(), 3)),
									(float) (vElement.getValue().getSourceX() + inp
											.getXRelToElement()) + 10,
									(float) (vElement.getValue().getSourceY() + inp
											.getYRelToElement()) + 8);
						}

						// durchlaufen der ausgaenge
						for (Output out : editorModel.getCircuitModel()
								.getUnmodifableElementsOnEditor()
								.get(vElement.getValue().getElementsName())
								.getOutputs().values()) {
							// es werden nur die ersten 3 buchstaben des
							// outputnamens angezeigt
							g2d.drawString(
									out.getOuterName().substring(
											0,
											Math.min(out.getOuterName()
													.length(), 3)),
									(float) (vElement.getValue().getSourceX() + out
											.getXRelToElement())
											- Math.min(out.getOuterName()
													.length(), 3) * 8,
									(float) (vElement.getValue().getSourceY() + out
											.getYRelToElement()) + 8);
						}
					}

				} else {
					// g2d.setColor(Color.BLACK);
					g2d.draw(vElement.getValue().getDesign());
				}
			}
		}
	}

	/**
	 * Private Hilfsmethode zum Zeichnen der Leitungen
	 * 
	 * @param g2d
	 *            Graphics2D Objekt aus der paintComponent-Methode
	 * 
	 * @param doNotClip
	 *            - Flag dies festlegt, ob alle Leitungen gezeichnet werden
	 *            sollen, oder nur die sichtbaren
	 */
	private void paintConnections(Graphics2D g2d, boolean doNotClip) {
		// falls gerade eine neue verbindung erstellt wird, wird diese
		// gezeichnet
		if (newConnection != null) {
			g2d.setColor(Color.BLACK);
			g2d.draw(newConnection.getPath());
		}

		// die markierten pfade werden zunaechst aus den nicht-markierten pfaden
		// geloescht
		paths.removeAll(markedPaths);

		// zeichnen der nicht-markierten verbindungen
		for (int i = 0; i < paths.size(); i++) {
			// hier wird ueberprueft, ob die linie gezeichnet werden muss. soll
			// normal auf den bearbeitungsbereich gezeichnet werden, wird nur
			// der sichtbare ausschnitt gezeichnet
			if (doNotClip || paths.get(i).getPath().intersects(visibleRect)) {
				// sind start und endbauteil der linie vorhanden, wird diese
				// gezeichnet, falls nicht wird sie geloescht
				if (!vElements.containsKey(paths.get(i).getSource()
						.getMySuperElement().getName())
						|| !vElements.containsKey(paths.get(i).getTarget()
								.getMySuperElement().getName())) {
					removedPaths.add(paths.get(i));
				} else {
					g2d.setColor(Color.BLACK);

					g2d.draw(paths.get(i).getPath());
				}
			}
		}

		// zeichnen der markierten linien, analog zu oben
		for (int i = 0; i < markedPaths.size(); i++) {
			if (!vElements.containsKey(markedPaths.get(i).getSource()
					.getMySuperElement().getName())
					|| !vElements.containsKey(markedPaths.get(i).getTarget()
							.getMySuperElement().getName())) {
				removedPaths.add(markedPaths.get(i));
			} else {
				if (markedPaths.get(i).getPath().intersects(visibleRect)) {
					g2d.setColor(Color.RED);
					g2d.draw(markedPaths.get(i).getPath());
				}
			}
		}

		// zusammenfuehren der markierten und nicht-markierten liien und
		// loeschen der linien, die kein start oder endbauteil mehr haben
		paths.addAll(markedPaths);
		paths.removeAll(removedPaths);
		removedPaths.clear();
	}

	/**
	 * Private Hilfsmethode zum Zeichnen der Inputs und Outputs
	 * 
	 * @param g2d
	 *            Graphics2D Objekt aus der paintComponent-Methode
	 * 
	 * @param Flag
	 *            , die festlegt ob alle Input und Output-Objekte gezeichnet
	 *            werden sollen, oder nur die sichtbare
	 */
	private void paintInputsAndOutputs(Graphics2D g2d, boolean doNotClip) {
		// zeichnen der ein- und ausgaenge
		for (Map.Entry<String, LogicViewElement> vElement : vElements
				.entrySet()) {
			if (doNotClip
					|| vElement.getValue().getDesign().intersects(visibleRect)) {
				// speichern der absoluten koordinaten des bauteils
				// fuer das setzen der inputs nachher noetig
				double absX = vElement.getValue().getSourceX();
				double absY = vElement.getValue().getSourceY();

				LogicType lType = editorModel.getCircuitModel()
						.getUnmodifableElementsOnEditor()
						.get(vElement.getValue().getElementsName()).getType();
				// beim boomel werden die ein- und ausgaenge nicht gezeichnet
				if (lType != LogicType.NODE) {

					// bei schalter und taktgeber werden die eingaenge nicht
					// gezeichnet, sind aber intern fuer die simulation
					// vorhanden
					if (lType != LogicType.SWITCH && lType != LogicType.CLOCK) {
						// zugriff auf die zugehoerigen inputs des
						// logicviewelements
						Map<String, Input> inputs = this.editorModel
								.getCircuitModel()
								.getUnmodifableElementsOnEditor()
								.get(vElement.getValue().getElementsName())
								.getInputs();

						// es wird nun durch die inputs iteriert und diese
						// graphisch
						// als kreis dargestellt
						for (Map.Entry<String, Input> m : inputs.entrySet()) {
							double relX = m.getValue().getXRelToElement();
							double relY = m.getValue().getYRelToElement();
							g2d.setColor(UserSettings.inputColor);
							g2d.fillOval((int) (absX + relX),
									(int) (absY + relY),
									UtilityConstants.IO_RADIUS,
									UtilityConstants.IO_RADIUS);
							g2d.setColor(Color.BLACK);
							g2d.drawOval((int) (absX + relX),
									(int) (absY + relY),
									UtilityConstants.IO_RADIUS,
									UtilityConstants.IO_RADIUS);
						}
					}

					// bei lampen wird der ausgang nicht gezeichnet, ist aber
					// intern
					// fuer die simulation vorhanden
					if (lType != LogicType.LAMP) {

						// zugriff auf die zugehoerigen outputs des
						// logicviewelements
						Map<String, Output> outputs = this.editorModel
								.getCircuitModel()
								.getUnmodifableElementsOnEditor()
								.get(vElement.getValue().getElementsName())
								.getOutputs();

						// es wird nun durch die outputs iteriert und diese
						// graphisch als kreis dargestellt
						for (Map.Entry<String, Output> m : outputs.entrySet()) {
							double relX = m.getValue().getXRelToElement();
							double relY = m.getValue().getYRelToElement();
							g2d.setColor(UserSettings.outputColor);
							g2d.fillOval((int) (absX + relX),
									(int) (absY + relY),
									UtilityConstants.IO_RADIUS,
									UtilityConstants.IO_RADIUS);
							g2d.setColor(Color.BLACK);
							g2d.drawOval((int) (absX + relX),
									(int) (absY + relY),
									UtilityConstants.IO_RADIUS,
									UtilityConstants.IO_RADIUS);
						}
					}
				}
			}
		}
	}

	/**
	 * Abhaengig vom uebergebenen Objekt werden verschiedene Operationen auf den
	 * Attributen der <code>EditorArea</code> ausgefuehrt, um diese an das
	 * <code>EditorModel</code> anzupassen.
	 */
	@Override
	public void update(Observable observable, Object data) {
		// bekommt in data ein message-objekt, dass den messagetyp und die
		// ben�tigten objekte (gatter...) beinhaltet
		// hier werden auch alle ConnectorPath Objekte generiert, dabei
		// ist darauf zu achten, dass bei den Attributen Input und Output
		// Klone erzeugt werden, da ansonsten Seiteneffekte auftreten k�nnen
		if (data instanceof EditorMessage) {
			EditorMessage msg = (EditorMessage) data;
			switch (msg.getMsgType()) {

			// es soll ein neues bauteil hinzugefuegt werden
			case ADD_ELEMENT:
				LogicEditorElement toAdd = msg.getObjects().get(0);
				Point2D loc = new Point2D.Double(toAdd.getXCoord(),
						toAdd.getYCoord());

				// falls es sich um ein selbstdefiniertes bauteil handelt, wird
				// entsprechend reagiert
				if (toAdd.getType() == LogicType.SELFDEFINED) {
					vElements.put(
							toAdd.getName(),
							new LogicViewElement(loc,
									UtilityLogicDesigns
											.getLogicSelfdefinedDesign(loc
													.getX(), loc.getY(), Math
													.max(toAdd.getInputs()
															.size(), toAdd
															.getOutputs()
															.size())), toAdd
											.getName()));
				} else {
					vElements.put(
							toAdd.getName(),
							new LogicViewElement(loc, UtilityLogicDesigns
									.getLogicDesign(toAdd.getType(),
											loc.getX(), loc.getY()), toAdd
									.getName()));
				}
				checkChangeSizeNecessary();
				break;

			// es sollen elemente geloescht werden. loescht die in der liste
			// msg.getObjects() gespeicherten elemente aus der map vElements
			case DELETE_ELEMENTS:
				List<LogicEditorElement> toDel = msg.getObjects();

				// iteriert ueber die liste der zu loeschenden elemente
				for (LogicEditorElement lEE : toDel) {
					vElements.remove(lEE.getName());
					markedVElements.remove(lEE.getName());
				}

				checkChangeSizeNecessary();
				break;

			// elemente wurden verschoben - setzt die koordinaten der
			// entsprechenden objecte in der map vElements neu und berechnet die
			// pfade neu
			case MOVE_ELEMENTS:
				List<LogicEditorElement> eElements = msg.getObjects();

				// aktualisieren der koordinaten der verschoben elemente
				for (LogicEditorElement eElement : eElements) {
					vElements.get(eElement.getName()).setSourceX(
							eElement.getXCoord());
					vElements.get(eElement.getName()).setSourceY(
							eElement.getYCoord());
					vElements.get(eElement.getName()).resetDesign(
							eElement.getType(),
							eElement.getXCoord(),
							eElement.getYCoord(),
							Math.max(eElement.getInputs().size(), eElement
									.getOutputs().size()));
				}

				// pfade werden neu berechnet
				for (int i = 0; i < paths.size(); i++) {
					paths.get(i).updatePath();
				}
				// ueberpruefen, ob der bearbeitungsbereich vergroessert werden
				// muss oder verkleinert werden kann
				checkChangeSizeNecessary();
				break;

			// setzen einer neuen verbindung
			case SET_CONNECTION:
				// erstellen einer neuen verbindung
				ConnectorPath connection = new ConnectorPath(
						msg.getOutputOfConnection(), msg.getInputOfConnection());
				connection.updatePath();
				paths.add(connection);
				break;

			// loeschen einer verbindung
			case DELETE_CONNECTION:
				// loeschen einer verbindung
				Input input = msg.getInputOfConnection();
				Output output = msg.getOutputOfConnection();

				// suchen nach der leitung, die durch die objecte input und
				// output eindeutig festgelegt ist
				for (int i = 0; i < markedPaths.size(); i++) {
					if (markedPaths.get(i).getTarget().equals(input)
							&& markedPaths.get(i).getSource().equals(output)) {
						paths.remove(markedPaths.get(i));
						markedPaths.remove(i);
						break;
					}
				}
				break;

			// loescht mehrere leitungen
			case DELETE_CONNECTIONS:
				Map<Input, Output> deleteCon = msg.getConnectionMap();

				// suchen der leitungen, die jeweils durch die paare von input
				// und output objekten eindeutig festgelegt sind
				for (Map.Entry<Input, Output> m : deleteCon.entrySet()) {
					for (int i = 0; i < markedPaths.size(); i++) {
						if (markedPaths.get(i).getTarget().equals(m.getKey())
								&& markedPaths.get(i).getSource()
										.equals(m.getValue())) {
							paths.remove(markedPaths.get(i));
						}
					}
				}

				markedPaths.clear();
				break;

			// bauteil wurde importiert
			case IMPORT_COMPONENT:
				List<LogicEditorElement> editorElements = msg.getObjects();
				createViewElements(editorElements);
				iArea.addInfoText("Bauteil "
						+ this.editorModel.getCircuitModel().getName()
						+ " importiert");
				break;

			// schaltungen wurde geladen
			case LOAD_CIRCUIT:
				List<LogicEditorElement> ediElements = msg.getObjects();
				createViewElements(ediElements);
				checkChangeSizeNecessary();
				iArea.addInfoText("Schaltung "
						+ this.editorModel.getCircuitModel().getName()
						+ " geladen");
				break;

			// schaltungstyp hat sich auf schaltnetz geaendert
			case IS_LOGICNET:
				this.typeArea.setToLogicNet();
				break;

			// schaltungstyp hat sich auf schaltwerk geaendert
			case IS_LOGICCIRCUIT:
				this.typeArea.setToLogicCircuit();
				break;

			// schaltungstyp ist leer
			case IS_DEFAULT:
				this.typeArea.setToDefault();
				break;

			case IS_UNKNOWN:
				this.typeArea.setToUnknown();
				break;

			// es wurde eine neue schaltung erstellt
			case NEW_CIRCUIT:
				markedVElements.clear();
				removedPaths.clear();
				paths.clear();
				vElements.clear();
				markedPaths.clear();
				iArea.addInfoText("Neue Schaltung angelegt");
				break;

			// die schaltung wurde gespeichert
			case SAVE_CIRCUIT:
				iArea.addInfoText("Schaltung gespeichert");
				break;

			// bauteile sollen am raster ausgerichtet werden
			case RASTER_POSITIONING:
				List<LogicEditorElement> edElements = msg.getObjects();
				for (LogicEditorElement lEE : edElements) {
					vElements.get(lEE.getName()).setSourceX(lEE.getXCoord());
					vElements.get(lEE.getName()).setSourceY(lEE.getYCoord());
					vElements.get(lEE.getName()).resetDesign(
							lEE.getType(),
							lEE.getXCoord(),
							lEE.getYCoord(),
							Math.max(lEE.getInputs().size(), lEE.getOutputs()
									.size()));
				}

				for (int i = 0; i < paths.size(); i++) {
					paths.get(i).updatePath();
				}

				this.repaint();
				break;

			// element wurde umbenannt
			case REFACTORED_ELEMENT:
				String[] renameElements = msg.getoldNameNewName();
				vElements.get(renameElements[0]).setElementsName(
						renameElements[1]);
				vElements.put(renameElements[1],
						vElements.get(renameElements[0]));
				vElements.remove(renameElements[0]);

			default:
				break;
			}
		}

		// nach dem updaten wird die editoare neu gezeichnet
		this.repaint();
		this.revalidate();
	}

	/**
	 * Erzeugt aus einer Liste von LogicEditorElements zugehoerige
	 * LogicViewElemente sowie die Verbindungen zwischen ihnen. Loescht dabei
	 * die vorhandenen Bauteile und Leitungen
	 * 
	 * @param eElements
	 *            Liste der LogicEditorElements
	 */
	private void createViewElements(List<LogicEditorElement> eElements) {
		// loeschen der bisherigen bauteile und leitungen
		vElements.clear();
		markedPaths.clear();
		markedVElements.clear();
		removedPaths.clear();
		paths.clear();
		LogicEditorElement eElement;
		Map<String, Input> inputs = new HashMap<String, Input>();
		ConnectorPath path;
		double xCoord = 0;
		double yCoord = 0;

		// erzeugen der logicviewelemente
		for (int i = 0; i < eElements.size(); i++) {
			eElement = eElements.get(i);
			xCoord = eElement.getXCoord();
			yCoord = eElements.get(i).getYCoord();
			Point2D loc = new Point2D.Double(xCoord, yCoord);

			// bei selbstdefinierten bauteilen wird anders vorgegangen
			if (eElement.getType() == LogicType.SELFDEFINED) {
				vElements.put(
						eElement.getName(),
						new LogicViewElement(loc,
								UtilityLogicDesigns.getLogicSelfdefinedDesign(
										loc.getX(), loc.getY(), Math.max(
												eElement.getInputs().size(),
												eElement.getOutputs().size())),
								eElement.getName()));
			} else {
				vElements.put(
						eElement.getName(),
						new LogicViewElement(
								new Point2D.Double(xCoord, yCoord),
								UtilityLogicDesigns.getLogicDesign(
										eElement.getType(), xCoord, yCoord),
								eElement.getName()));
			}

			inputs = eElement.getInputs();

			// setzen der leitungen zwischen den bauteilen
			for (Map.Entry<String, Input> m : inputs.entrySet()) {
				if (m.getValue().getSourceOutput() != null) {
					path = new ConnectorPath(m.getValue().getSourceOutput(),
							m.getValue());
					path.updatePath();
					paths.add(path);
				}
			}
		}
	}

	/**
	 * Ueberprueft, ob ein Bauteil an den Grenzen des aktuellen Bereichs
	 * hinzugefuegt wurde. Gegebenenfalls wird der aktuelle Bearbeitungsbereich
	 * vergroessert
	 */
	public void checkChangeSizeNecessary() {
		maxXPos = (int) ((getMaxXValue() + 45) * tabPane.getZoomFactor());
		maxYPos = (int) ((getMaxYValue() + 45) * tabPane.getZoomFactor());

		this.setPreferredSize(new Dimension(Math.max(800, maxXPos), Math.max(
				800, maxYPos)));
		this.repaint();
		this.revalidate();
	}

	/**
	 * Testet ob zwei Shapes sich schneiden.
	 * 
	 * @param s1
	 *            erstes Shape
	 * @param s2
	 *            zweites Shape
	 * @return <code>true</code> wenn sie sich schneiden, <code>false</code>
	 *         sonst
	 */
	public boolean shapesIntersect(Shape s1, Shape s2) {
		Area a1 = new Area(s1);
		Area a2 = new Area(s2);

		a1.intersect(a2);
		if (a1.isEmpty()) {
			return false;
		}
		return true;
	}

	/**
	 * Gibt die minimale x-Position aller Bauteile zurueck
	 * 
	 * @return minimale x-Position
	 */
	public int getMinXValue() {
		int minValue = 0;
		boolean firstSet = false;

		// durchlaeuft alle bauteile und sucht sich den kleinsten x-wert raus
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if (!firstSet) {
				minValue = (int) lVE.getValue().getDesign().getBounds()
						.getMinX();
				firstSet = true;
			} else if ((int) lVE.getValue().getDesign().getBounds().getMinX() < minValue) {
				minValue = (int) lVE.getValue().getDesign().getBounds()
						.getMinX();
			}
		}

		return minValue;
	}

	/**
	 * Gibt die minimale y-Position aller Bauteile zurueck
	 * 
	 * @return minimale y-Position
	 */
	public int getMinYValue() {
		int minValue = 0;
		boolean firstSet = false;

		// durchlaeuft alle bauteile und sucht sich den kleinsten y wert raus
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if (!firstSet) {
				minValue = (int) lVE.getValue().getDesign().getBounds()
						.getMinY();
				firstSet = true;
			} else if ((int) lVE.getValue().getDesign().getBounds().getMinY() < minValue) {
				minValue = (int) lVE.getValue().getDesign().getBounds()
						.getMinY();
			}
		}

		return minValue;
	}

	/**
	 * Gibt die maximale x-Position aller Bauteile zurueck
	 * 
	 * @return maximale x-Position
	 */
	public int getMaxXValue() {
		int maxValue = 0;

		// durchlaeuft alle bauteile und sucht sich den groessten x-wert raus
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if ((int) lVE.getValue().getDesign().getBounds().getMaxX() > maxValue) {
				maxValue = (int) lVE.getValue().getDesign().getBounds()
						.getMaxX();
			}
		}

		return maxValue;
	}

	/**
	 * Gibt die maximale y-Position aller Bauteile zurueck
	 * 
	 * @return maximale y-Position
	 */
	public int getMaxYValue() {
		int maxValue = 0;

		// durchlaeuft alle bauteile und sucht sich den gleichen y-wert raus
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if ((int) lVE.getValue().getDesign().getBounds().getMaxY() > maxValue) {
				maxValue = (int) lVE.getValue().getDesign().getBounds()
						.getMaxY();
			}
		}

		return maxValue;
	}

	/**
	 * Gibt die Namen aller <code>LogicViewElement</code>-Objekte, die markiert
	 * sind zurueck.
	 * 
	 * @return <code>List</code> - Namen der markierten
	 *         <code>LogicViewElement</code>-Objekte
	 */
	public List<String> getNamesOfSelectedElements() {
		List<String> selectedElements = new ArrayList<String>(
				markedVElements.keySet());
		return selectedElements;
	}

	/**
	 * Setzt die Markierungen aller <code>LogicViewElement</code>-Objekte bzw.
	 * <code>ConnectorPath</code>-Objekte auf <code>true</code>.
	 */
	public void selectAllElements() {
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			lVE.getValue().setMarked(true);
			markedVElements.put(lVE.getKey(), lVE.getValue());
		}

		for (int i = 0; i < paths.size(); i++) {
			paths.get(i).setMarked(true);
			markedPaths.add(paths.get(i));
		}
		this.repaint();
		this.revalidate();
	}

	/**
	 * Markiert alle <code>LogicViewElement</code>-Objekte bzw.
	 * <code>ConnectorPath</code>-Objekte, markierungsrechteck schneiden, bzw.
	 * im Rechteck liegen.
	 * 
	 */
	private void selectElements() {
		// zuerst werden alle Elemente demarkiert
		markElementsAsFalse();

		// es wird ueberprueft, ob elemente das rechteck schneiden
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if (lVE.getValue().getDesign().intersects(markTangle)) {
				lVE.getValue().setMarked(true);
				markedVElements.put(lVE.getKey(), lVE.getValue());
			}
		}

		// es wird ueberprueft, ob verbindungen das rechteck schneiden
		for (int i = 0; i < paths.size(); i++) {
			if (paths.get(i).getPath().intersects(markTangle)) {
				paths.get(i).setMarked(true);
				markedPaths.add(paths.get(i));
			}
		}

		repaint();
		revalidate();
	}

	/**
	 * Markiert das <code>LogicViewElement</code>-Objekt bzw.
	 * <code>ConnectorPath</code>-Objekt, das auf dem uebergeben Punkt in Pixel
	 * liegt.
	 * 
	 * @param clickedPoint
	 *            <code>Point</code> - vom Benutzer ausgewaehlter Bildpunkt in
	 *            Pixel, zum Markieren von Elementen
	 */
	public void selectElement(Point2D clickedPoint) {
		// zuerst werden alle Elemente demarkiert
		markElementsAsFalse();

		// es wird ueberprueft, ob ein Element angeklickt wurde und ggf markiert
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if (lVE.getValue().getDesign().contains(clickedPoint)) {
				lVE.getValue().setMarked(true);
				markedVElements.put(lVE.getKey(), lVE.getValue());
			}
		}

		// um linien anklicken besser anklicken zu können, wird hier ein
		// rechteck von 4x4 pixeln erstellt (klickbereich wird somit groesser
		// gemacht)
		Rectangle2D rec = new Rectangle2D.Double(Math.max(
				clickedPoint.getX() - 2, 0), Math.max(clickedPoint.getY() - 2,
				0), 4, 4);

		// ueberpruefen ob eine linie markiert werden muss
		for (int i = 0; i < paths.size(); i++) {
			if (paths.get(i).getPath().intersects(rec)) {
				paths.get(i).setMarked(true);
				markedPaths.add(paths.get(i));
			}
		}

		repaint();
		revalidate();
	}

	/**
	 * Setzt die Markierung aller LogicViewElemente auf false
	 */
	private void markElementsAsFalse() {
		// demarkieren aller bauteile
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			lVE.getValue().setMarked(false);
		}

		// demarkierten aller verbindungen
		for (int i = 0; i < paths.size(); i++) {
			paths.get(i).setMarked(false);
		}
		markedVElements.clear();
		markedPaths.clear();
	}

	/**
	 * Aendert das interne Flag, ob das Raster gezeichnet werden soll
	 */
	public void changeRasterVisibility() {
		showRaster = !showRaster;
		this.repaint();
	}

	/**
	 * Diese Methode gibt alle Bauteile der Schaltung zurueck.
	 * 
	 * @return <code>List</code> - alle <code>LogicViewElement</code>-Objekte
	 */
	public List<LogicViewElement> getLogicViewElements() {
		return Collections.unmodifiableList(new ArrayList<LogicViewElement>(
				this.vElements.values()));
	}

	/**
	 * Gibt die Liste der Verbindungen zurueck
	 * 
	 * @return Liste der Verbindungen
	 */
	public List<ConnectorPath> getConnectorPaths() {
		return Collections.unmodifiableList(paths);
	}

	/**
	 * Gibt eine Map der markierten Elemente zur�ck
	 * 
	 * @return <code>Map</code> - mit den markierten
	 *         <code>LogicViewElements</code>
	 */
	public Map<String, LogicViewElement> getMarkedLogicViewElements() {
		return Collections.unmodifiableMap(markedVElements);
	}

	/**
	 * Diese Methode gibt die Namen aller markierten ConnectorPaths zurueck
	 * 
	 * @return <code>List</code> - Namen aller markierten
	 *         <code>ConnectorPath</code>-Objekte
	 */
	public List<ConnectorPath> getMarkedConnectorPaths() {
		List<ConnectorPath> returnMarkedPaths = new ArrayList<ConnectorPath>();
		// es muss hier die liste kopiert werden
		for (int i = 0; i < markedPaths.size(); i++) {
			returnMarkedPaths.add(markedPaths.get(i));
		}
		return returnMarkedPaths;
	}

	/**
	 * Diese Methode gibt das <code>ComponentPanel</code> zurueck.
	 * 
	 * @return <code>ComponentPanel</code> - das <code>ComponentPanel</code>
	 */
	public ComponentPanel getComponentPanel() {
		return this.compPanel;
	}

	/**
	 * Prueft ob ein Element an der Stelle x in Pixel bereits selektiert ist
	 * oder nicht
	 * 
	 * @param x
	 *            <code>Point</code> - ausgewaehlter Bildpunkt in Pixel
	 * 
	 * @return <code>boolean</code> - <code>true</code>, falls bereits
	 *         ausgewaehlt; <code>false</code> falls es noch nicht markiert ist,
	 *         bzw keines angeklickt wurde
	 */
	public boolean isElementSelected(Point2D x) {

		// isMarked wird genau dann auf true gesetzt, wenn ein element
		// angeklickt wurde
		// und dieses bereits markiert ist
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if (lVE.getValue().getDesign().contains(x)
					&& lVE.getValue().isMarked()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Gibt das <code>LogicViewElement</code> an dem Punkt wieder
	 * 
	 * @param x
	 *            <code>Point</code> - ausgewaehlter Bildpunkt in Pixel
	 * 
	 * @return <code>LogicViewElement</code> - das Bauteil das diesen Punkt
	 *         beinhaltet - null wenn kein Element dort liegt
	 */
	public LogicViewElement containsElement(Point2D x) {
		for (Map.Entry<String, LogicViewElement> lVE : vElements.entrySet()) {
			if (lVE.getValue().getDesign().contains(x)) {
				return lVE.getValue();
			}
		}

		return null;
	}

	/**
	 * Erstellt ein neues Markierungsrechteck mit den Anfangskoordinaten
	 * 
	 * @param xStart
	 *            x-Koordinate Startpunkt (links oben)
	 * @param yStart
	 *            y-Koordinate Startpunkt (links oben)
	 * @param xEnd
	 *            x-Koordinate Endpunkt (rechts unten)
	 * @param yEnd
	 *            y-Koordinate Endpunkt (rechts unten)
	 * @return markTangle - erzeugtes Markierungsrechteck
	 */
	public Rectangle2D initializeMarkTangle(double xStart, double yStart,
			double xEnd, double yEnd) {
		this.startXMarkTangle = xStart;
		this.startYMarkTangle = yStart;
		this.markTangle = new Rectangle2D.Double(xStart, yStart, xEnd - xStart,
				yEnd - yStart);
		this.repaint();
		this.revalidate();
		return markTangle;
	}

	/**
	 * Aendert bei dem bereits erstellten Markierungsrechteck den Endpunkt Diese
	 * Methode ermoeglicht das Vergroessern und Verkleinern des
	 * Markierungsrechtecks
	 * 
	 * @param xEnd
	 *            neuer x-Wert des Endpunktes
	 * @param yEnd
	 *            neuer y-Wert des Endpunktes
	 * @param markTangle
	 *            Markierungsrechteck
	 */
	public Rectangle2D moveMarkTangle(double xEnd, double yEnd) {

		double newWidth = xEnd - startXMarkTangle;
		double newHeight = yEnd - startYMarkTangle;

		// wurde das markierungsrechteck nach rechts unten vergroessert, kann
		// man einfach
		// die neuen werte setzen
		if (newWidth >= 0 && newHeight >= 0) {
			markTangle.setRect(startXMarkTangle, startYMarkTangle, newWidth,
					newHeight);
			// wurde das markierungsrechteck nach rechts oben vergroessert, muss
			// man den ursprung des rechtecks neu berechnen (neuen y-Wert)
		} else if (newWidth >= 0 && newHeight < 0) {
			markTangle.setRect(startXMarkTangle, yEnd, newWidth, -newHeight);
			// wurde das markierungsrechteck nach links unten vergroessert, muss
			// man den ursprung des rechtecks neu berechnen (neuen x-Wert)
		} else if (newWidth < 0 && newHeight >= 0) {
			markTangle.setRect(xEnd, startYMarkTangle, -newWidth, newHeight);
			// wurde das markierungsrechteck nach links oben vergroessert, muss
			// man den ursprung neu berechnen (neuen x-Wert, neuen y-Wert)
		} else {
			markTangle.setRect(xEnd, yEnd, -newWidth, -newHeight);
		}

		selectElements();
		this.repaint();
		this.revalidate();
		return markTangle;
	}

	/**
	 * Diese Methode loescht das Markierungsrechteck Wird vom EditorAreaListener
	 * aufgerufen
	 */
	public void removeMarkTangle() {
		this.markTangle = null;
		this.repaint();
		this.revalidate();
	}

	/**
	 * Erstellt eine neue Verbindung mit einem Startpunkt. Der Endpunkt stimmt
	 * erstmal mit dem Startpunkt ueberein
	 * 
	 * @param startPoint
	 *            Startpunkt
	 */
	public void initializeNewConnection(Point2D startPoint) {
		this.startPointConnection = new Point2D.Double(startPoint.getX(),
				startPoint.getY());
		this.newConnection = new ConnectorPath(null, null);
		this.newConnection.setPath(startPoint, startPoint);

	}

	/**
	 * Setzt den Endpunkt der neu erstellten Linie neu. Wird fuer das Ziehen der
	 * Linie benoetigt
	 * 
	 * @param endPoint
	 *            neuer Endpunkt
	 */
	public void moveNewConnection(Point2D endPoint) {
		this.newConnection.setPath(startPointConnection, endPoint);
		this.repaint();
		this.revalidate();
	}

	/**
	 * Loescht die neu erstellte Linie. Dies ist der Fall, wenn der Benutzer
	 * zwei Eingaenge oder Ausgaenge miteinander verbinden will, bzw. beim
	 * zweiten Klick keinen Eingang oder Ausgang anklickt
	 */
	public void removeNewConnection() {
		this.newConnection = null;
		this.repaint();
		this.revalidate();
	}

	/**
	 * Richtet die Bauteile am Raster aus
	 * 
	 * @return true, falls sich dabei Bauteile schneiden, sonst false
	 */
	public boolean positioningToRaster() {
		int x = 0;
		int y = 0;
		for (LogicViewElement elem : vElements.values()) {

			x = (int) elem.getSourceX();
			y = (int) elem.getSourceY();

			// x-wert der bauteile wird am nächstgelegenen x-wert einer
			// vertikalen rasterlinie ausgerichtet
			if (x % UtilityConstants.RASTER_SIZE >= UtilityConstants.RASTER_SIZE / 2) {
				elem.setSourceX(x
						+ (UtilityConstants.RASTER_SIZE - (x % UtilityConstants.RASTER_SIZE)));
			} else {
				elem.setSourceX(x - (x % UtilityConstants.RASTER_SIZE));
			}

			// y-wert der bauteile wird am nächstgelegenen y-wert einer
			// horizontalen rasterlinie ausgerichtet
			if (y % UtilityConstants.RASTER_SIZE >= UtilityConstants.RASTER_SIZE / 2) {
				elem.setSourceY(y
						+ (UtilityConstants.RASTER_SIZE - (y % UtilityConstants.RASTER_SIZE)));
			} else {
				elem.setSourceY(y - (y % UtilityConstants.RASTER_SIZE));
			}

			LogicEditorElement lElem = editorModel.getCircuitModel()
					.getUnmodifableElementsOnEditor()
					.get(elem.getElementsName());

			// die designs der bauteile werden entsprechend aktualisiert
			elem.resetDesign(lElem.getType(), elem.getSourceX(), elem
					.getSourceY(), Math.max(lElem.getInputs().size(), lElem
					.getOutputs().size()));
		}
		return doIntersectingObjectsExist();
	}

	/**
	 * Methode, die ueberprueft, ob sich zwei Elemente schneiden
	 * 
	 * @return false falls kein Schnittpunkt, sonst true
	 */
	public boolean doIntersectingObjectsExist() {
		List<LogicViewElement> lVEs = new ArrayList<LogicViewElement>(
				vElements.values());

		// durchlaufen der bauteile und ueberpruefen ob sich zwei bauteile
		// schneiden (effizienter durchlauf, da zwei bauteile immer nur einmal
		// verglichen werden)
		for (int i = 0; i < lVEs.size(); i++) {
			for (int j = i + 1; j < lVEs.size(); j++) {
				if (shapesIntersect(lVEs.get(i).getDesign(), lVEs.get(j)
						.getDesign())) {
					return true;
				}
			}

		}
		return false;
	}

	/**
	 * Setzt das <code>JScrollPane</code> des Bearbeitungsbereichs
	 * 
	 * @param eScroller
	 *            <code>JScrollPane</code> des Bearbeitungsbereich
	 */
	public void setScrollPane(JScrollPane eScroller) {
		this.eScroller = eScroller;
		this.showRaster = false;
	}

	/**
	 * Gibt die <code>InfoArea</code> zurueck
	 * 
	 * @return <code>InfoArea</code>
	 */
	public InfoArea getiArea() {
		return iArea;
	}
}